1.创建新项目
2.数据表设计
2.1.表结构规划
https://docs.djangoproject.com/en/2.0/ref/models/instances/#django.db.models.Model.clean
from django.db import modelsfrom django.contrib.auth.models import Userfrom django.core.exceptions import ValidationErrorimport datetime# Create your models here.class Article(models.Model): #文章标题 title = models.CharField(max_length=255) #文章简介 brief = models.CharField(null=True,blank=True,max_length=255) #文章板坏 category = models.ForeignKey("Category") #文章内容 content = models.TextField("文章内容") #作者 author = models.ForeignKey("UserProfile") #文章发布时间,auto_now_add自动发布为发布时的时间 pub_date = models.DateTimeField(blank=True,null=True) #最后修改时间为修改的当前时间 last_modify = models.DateTimeField(auto_now=True) #文章置顶,默认是1000 priority = models.IntegerField("优先级",default=1000) #文章状态可选项 status_choice = (('draft',"草稿"), ('published',"已发布"), ('hidden','隐藏'), ) #文章状态 status = models.CharField(choices=status_choice,default='published',max_length=64) def __str__(self): return self.title def clean(self): # Don't allow draft entries to have a pub_date. if self.status == 'draft' and self.pub_date is not None: raise ValidationError(('Draft entries may not have a publication date.')) # Set the pub_date for published items if it hasn't been set already. if self.status == 'published' and self.pub_date is None: self.pub_date = datetime.date.today()class Comment(models.Model): #关联所属文章 article = models.ForeignKey(Article,verbose_name="所属文章") #顶级评论 parent_comment = models.ForeignKey('self',related_name='my_children',null=True) #评论及点赞可选项 comment_choice = ((1,'评论'), (2,'点赞')) #评论类型 comment_type = models.IntegerField(choices=comment_choice,default=1) #评论用户 user = models.ForeignKey("UserProfile") #评论内容 comment = models.TextField(blank=True,null=True) # 添加评论时间 date = models.DateField(auto_now_add=True) def __str__(self): return "%s,%s,%s" %(self.article,self.comment,self.date) def clean(self): if self.comment_type == 1 and self.comment is None: raise ValidationError("评论写点什么吧")class Category(models.Model): #板块名 name = models.CharField(max_length=64,unique=True) #板块简介 brief = models.CharField(null=True,blank=True,max_length=255) #顶级菜单 set_as_top_menu = models.BooleanField(default=False) #版主设置,可设置为空 admins = models.ManyToManyField("UserProfile",blank=True) #菜单位置 position_index = models.SmallIntegerField() def __str__(self): return self.nameclass UserProfile(models.Model): #关联到django的的User user = models.OneToOneField(User) #用户名 name = models.CharField(max_length=32) #个人签名 signature = models.CharField(max_length=255,blank=True,null=True) #头像 head_img = models.ImageField(height_field=200,width_field=200) def __str__(self): return self.name
2.2.生成表
3.注册django admin
from django.contrib import adminfrom bbs import models# Register your models here.class ArticleAdmin(admin.ModelAdmin): list_display = ('title','category','author','pub_date','last_modify','status','priority')class CommentAdmin(admin.ModelAdmin): list_display = ('article','parent_comment','comment_type','comment','user','date')class CategoryAdmin(admin.ModelAdmin): list_display = ('name','set_as_top_menu','position_index')admin.site.register(models.Article,ArticleAdmin)admin.site.register(models.Comment,CommentAdmin)admin.site.register(models.UserProfile)admin.site.register(models.Category,CategoryAdmin)
4.添加超级用户
5.登录添加内容
5.1.添加文章
5.2.添加评论
5.3.为文章添加图片
5.3.1.最新表结构
from django.db import modelsfrom django.contrib.auth.models import Userfrom django.core.exceptions import ValidationErrorimport datetime# Create your models here.class Article(models.Model): #文章标题 title = models.CharField(max_length=255) #文章简介 brief = models.CharField(null=True,blank=True,max_length=255) #文章板坏 category = models.ForeignKey("Category") #文章内容 content = models.TextField("文章内容") #作者 author = models.ForeignKey("UserProfile") #文章发布时间,auto_now_add自动发布为发布时的时间 pub_date = models.DateTimeField(blank=True,null=True) #最后修改时间为修改的当前时间 last_modify = models.DateTimeField(auto_now=True) #文章置顶,默认是1000 priority = models.IntegerField("优先级",default=1000) # 文图 head_img = models.ImageField("文章配图") #文章状态可选项 status_choice = (('draft',"草稿"), ('published',"已发布"), ('hidden','隐藏'), ) #文章状态 status = models.CharField(choices=status_choice,default='published',max_length=64) def __str__(self): return self.title def clean(self): # Don't allow draft entries to have a pub_date. if self.status == 'draft' and self.pub_date is not None: raise ValidationError(('Draft entries may not have a publication date.')) # Set the pub_date for published items if it hasn't been set already. if self.status == 'published' and self.pub_date is None: self.pub_date = datetime.date.today()class Comment(models.Model): #关联所属文章 article = models.ForeignKey(Article,verbose_name="所属文章") #顶级评论 parent_comment = models.ForeignKey('self',related_name='my_children',null=True,blank=True) #评论及点赞可选项 comment_choice = ((1,'评论'), (2,'点赞')) #评论类型 comment_type = models.IntegerField(choices=comment_choice,default=1) #评论用户 user = models.ForeignKey("UserProfile") #评论内容 comment = models.TextField(blank=True,null=True) # 添加评论时间 date = models.DateField(auto_now_add=True) def __str__(self): return "%s,%s,%s" %(self.article,self.parent_comment,self.comment) def clean(self): if self.comment_type == 1 and len(self.comment) == 0: raise ValidationError("评论写点什么吧")class Category(models.Model): #板块名 name = models.CharField(max_length=64,unique=True) #板块简介 brief = models.CharField(null=True,blank=True,max_length=255) #顶级菜单 set_as_top_menu = models.BooleanField(default=False) #版主设置,可设置为空 admins = models.ManyToManyField("UserProfile",blank=True) #菜单位置 position_index = models.SmallIntegerField() def __str__(self): return self.nameclass UserProfile(models.Model): #关联到django的的User user = models.OneToOneField(User) #用户名 name = models.CharField(max_length=32) #个人签名 signature = models.CharField(max_length=255,blank=True,null=True) #头像 head_img = models.ImageField(height_field=200,width_field=200,blank=True) def __str__(self): return self.name
5.3.2.重新应用表
5.3.3.添加文章图片
5.3.4.图片默认被保存的路径
5.3.5.图片保存修改
django 自带图片保存,修改字段:
head_img = models.ImageField("文章配图",upload_to="uploads")
上传图片:
自动创建uploads并保存图片
5.4.配置动态板块
5.4.1.配置views
from django.shortcuts import renderfrom bbs import models# Create your views here.def index(request): #或许所有的的板块 category_list = models.Category.objects.filter(set_as_top_menu=True).order_by("position_index") return render(request,'bbs/index.html',{ 'category_list':category_list})
5.4.2.配置返回页面
返回页面直接配置base即可
https://v3.bootcss.com/examples/navbar-fixed-top/
.......
5.4.3.查看返回板块
5.4.4.增加多的板块
5.4.5.配置urls
如果点击板块,只需要返回同一个页面,需要引入一个url,如:http://127.0.0.1:8000/bbs/category/1/
from django.conf.urls import url,includefrom bbs import viewsurlpatterns = [ url(r'^$', views.index), url(r'category/(\d+)/$', views.category),]
5.4.6.配置views
from django.shortcuts import renderfrom bbs import models#单独将category列表取出category_list = models.Category.objects.filter(set_as_top_menu=True).order_by("position_index")# Create your views here.def index(request): return render(request,'bbs/index.html',{ 'category_list':category_list})def category(request,id): category_obj = models.Category.objects.get(id=id) return render(request, 'bbs/index.html',{ 'category_list':category_list, 'category_obj':category_obj})
5.4.7.配置base页面
........
5.4.8.查看返回
6.配置用户登录及退出
6.1.配置登录及注销方法
from django.shortcuts import renderfrom bbs import modelsfrom django.contrib.auth import login,logout,authenticatefrom django.contrib.auth.decorators import login_requiredfrom django.shortcuts import render,HttpResponse,HttpResponseRedirectcategory_list = models.Category.objects.filter(set_as_top_menu=True).order_by("position_index")# Create your views here.def index(request): return render(request,'bbs/index.html',{ 'category_list':category_list})def category(request,id): category_obj = models.Category.objects.get(id=id) return render(request, 'bbs/index.html',{ 'category_list':category_list, 'category_obj':category_obj})def acc_login(request): if request.method == 'POST': print(request.POST) user = authenticate(username=request.POST.get('username'), password=request.POST.get('password')) if user is not None: login(request,user) return HttpResponseRedirect('/bbs') else: login_err = "Worng user name or password" return render(request,'login.html',{ 'login_err':login_err}) return render(request,'login.html')def acc_logout(request): logout(request) return HttpResponseRedirect('/bbs')
6.2.配置url
from django.conf.urls import url,includefrom django.contrib import adminfrom bbs import viewsurlpatterns = [ url(r'^admin/', admin.site.urls), url(r'^bbs',include('bbs.urls')), url(r'login',views.acc_login,name='login'), url(r'logout',views.acc_logout,name='logout'),]
6.3.配置返回html
........
登录html 拷贝之前的登录页面
6.4.登录及退出
登录:
7.各个板块分开展示
7.1.每个板块增加文章
7.2.内容预览
7.2.1.各个专栏展示
7.2.2.全部展示所有的内容
....def category(request,id): category_obj = models.Category.objects.get(id=id) if category_obj.position_index == 1:#全部 article_list = models.Article.objects.filter(status='published') else: article_list = models.Article.objects.filter(category_id = category_obj.id,status='published') return render(request, 'bbs/index.html',{ 'category_list':category_list, 'category_obj':category_obj, 'article_list':article_list }).....
7.2.3.查看全部内容
7.3.默认路径访问所有内容
如:http://127.0.0.1:8000/bbs
def index(request): article_list = models.Article.objects.filter(status='published') return render(request,'bbs/index.html',{ 'category_list':category_list, 'article_list': article_list })
查看展示:
7.4.将全部增加选中样式
def index(request): category_obj = models.Category.objects.get(position_index=1) article_list = models.Article.objects.filter(status='published') return render(request,'bbs/index.html',{ 'category_list':category_list, 'article_list': article_list, 'category_obj':category_obj })
查看展示:
7.5.文章内容展示
7.5.1.展示文章标题及图片
修改index.html
{% extends 'base.html' %}{% block page-container %} {% for article in article_list %}{% endfor %}{% endblock %}{ { article.title }}
7.5.2.展示内容
7.5.3.图片无法展示
图片路径为http://127.0.0.1:8000/static/uploads/2.jpg
7.5.4.增加静态资源的路径
STATICFILES_DIRS = [ os.path.join(BASE_DIR, "statics"), os.path.join(BASE_DIR, "uploads") # '/var/www/static/',]
图片路径多了一个uploads,去掉可以访问
需要做的,就是讲url的路径截取,没有这样的方法,需要自定义标签
7.6.新增自定义标签
7.6.1.定义标签方法
#!/usr/bin/env python# -*- coding: utf-8 -*-from django import templatefrom django.utils.html import format_htmlregister = template.Library()@register.filterdef truncate_url(img_obj): print(img_obj.name) return img_obj.name.split("/",maxsplit=1)[-1]
7.6.2.静态页面load 自定义标签并使用方法
{% extends 'base.html' %}{% load custom %}{% block page-container %} {% for article in article_list %}{% endfor %}{% endblock %}{ { article.title }}
7.6.3.查看结果
7.7.配置静态展示
7.7.1.添加静态css
.page-container { border: 1px dashed darkcyan; padding-left: 150px;}.wrap-left { width: 75%; float: left; background-color: darkgoldenrod;}.wrap-right { width: 25%; float: left; background-color: darkolivegreen;}.clear-both { clear: both;}.footer { height: 300px; background-color: #1e0eff;}
7.7.2.配置index.html
{% extends 'base.html' %}{% load custom %}{% block page-container %}{% for article in article_list %}{% endfor %}{ { article.title }}right{% endblock %}
7.7.3.配置base.html
诗经源远 {% block page-container %}{% endblock %}Being young is an attitude!
7.7.4.页面展示
截图不完全,太大了
7.8.图片大小裁剪
7.8.1.index.html
{ { article.title }}
7.8.2.增加样式
custom.css
.article-head-img img { width: 230px; height: 130px;}
7.8.3.查看结果
7.9.字体展示在右边
修改index.html
......{ { article.title }}
7.10.增加间距
.article-box { padding-bottom: 10px;}
{ { article.title }}
查看展示:
7.11.增加边距去掉背景
#去掉背景 .wrap-left { width: 75%; float: left; }
#内边距 .article-box { padding-bottom: 10px;} #字体与图片距离.article-brief { margin-left: -170px;}
查看展示:
7.12.修改文章title标签
index.html
/*标题字体大小 */.article-title { font-size: 20px;}a { color: #333333;}a.active { text-decoration: none;}/*鼠标移动,颜色变化 */a:hover { color: #337ab7; text-decoration: none;}/*整个页面字体,好像然并卵 */body{ background-color: rgb(255, 255, 255); color: rgb(48, 48, 48); font-family: Arial, 微软雅黑, "Microsoft yahei", "Hiragino Sans GB", "冬青黑体简体中文 w3", "Microsoft Yahei", "Hiragino Sans GB", "冬青黑体简体中文 w3", STXihei, 华文细黑, SimSun, 宋体, Heiti, 黑体, sans-serif;}
7.13.添加点赞及作者信息
{ { article.title }}{ { article.author.name }} { { article.pub_date }} { { article.comment_set.select_related.count }}
查看展示:
8.点赞和评论分开
新增评论与点赞
8.1.新增自定义标签
#!/usr/bin/env python# -*- coding: utf-8 -*-from django import templatefrom django.utils.html import format_htmlregister = template.Library()@register.filterdef truncate_url(img_obj): print(img_obj.name) return img_obj.name.split("/",maxsplit=1)[-1]@register.simple_tagdef filter_comment(article_obj): #查询文章所有的评论与点赞 query_set = article_obj.comment_set.select_related() comments = { #评论 'comment_count':query_set.filter(comment_type=1).count(), #点赞 'thumb_count': query_set.filter(comment_type=2).count(), } return comments
8.2.修改index调用自定义方法获取内容
{ { article.author.name }} { { article.pub_date }} {% filter_comment article as comments %} { { comments.comment_count }} { { comments.thumb_count }}
8.3.查看返回
8.4.添加点赞与评论图标
组件图标地址http://v3.bootcss.com/components/
{ { article.author.name }} { { article.pub_date }} {% filter_comment article as comments %} { { comments.comment_count }} { { comments.thumb_count }}
查看返回
8.5.添加主题
{ { article.title }}{ { article.author.name }} { { article.pub_date }} {% filter_comment article as comments %} { { comments.comment_count }} { { comments.thumb_count }}{ { article.brief }}
8.5.1.配置主题样式
.article-brief-text{ margin-top: 10px; color: #999;}
8.5.2.查看返回
9.详细页面展示
9.1.增加返回url
from django.conf.urls import url,includefrom bbs import viewsurlpatterns = [ url(r'^$', views.index), url(r'category/(\d+)/$', views.category), url(r'detail/(\d+)/$', views.article_detail,name="article_detail"),]
9.2.增加返回方法
def article_detail(request,article_id): article_obj = models.Article.objects.get(id=article_id) return render(request,'bbs/article_detail.html',{ 'article_obj':article_obj})
9.3.新增返回页面
{% extends 'base.html' %}{ % load custom %}{ % block page-container %}{ { article_obj }}right{ % endblock %}
9.4.增加图片及文字
9.4.1.增加静态图标及文章展示
{% extends 'base.html' %}{% load custom %}{% block page-container %}{ { article_obj.title }}作者:{ { article_obj.author.name }} { { article_obj.pub_date }} {% filter_comment article_obj as comments %} { { comments.comment_count }}{ { article_obj }} { { article_obj.content }}right{% endblock %}
9.4.2.增加样式
.article-title-size { font-size: 30px;} #标题位置及颜色.article-title-brief { margin-top: 10px; color: #999;} #图片位置及占比.article-detail-head-img { margin-top: 25px; margin-bottom: 25px; width: 100%;} #文字间距.article-content { line-height: 30px}
9.4.3.方法修改增加板块
def article_detail(request,article_id): article_obj = models.Article.objects.get(id=article_id) return render(request,'bbs/article_detail.html',{ 'article_obj':article_obj, 'category_list': category_list,})
9.4.4.查看页面
9.5.添加评论及CSRF
9.5.1.新增评论输入框
base.html 新增继承block
base.html新增csrf
article_detail.html
{% extends 'base.html' %}{% load custom %}{% block page-container %}{ { article_obj.title }}作者:{ { article_obj.author.name }} { { article_obj.pub_date }} {% filter_comment article_obj as comments %} { { comments.comment_count }}{ { article_obj.content }}{% if request.user.is_authenticated %} {% endif %}right{% endblock %}{% block bottom-js %}{% endblock %}
9.5.2.新增url
from django.conf.urls import url,includefrom bbs import viewsurlpatterns = [ url(r'^$', views.index), url(r'category/(\d+)/$', views.category), url(r'detail/(\d+)/$', views.article_detail,name="article_detail"), url(r'comment/$', views.comment,name="post_comment"),]
9.5.3.新增返回方法
def comment(request): print(request.POST) return HttpResponse('xxx')
9.5.4.提交评论
输入正常评论:
9.6.增加登录评论
9.6.1.增减登录静态显示
{% if request.user.is_authenticated %} {% else %}{% endif %}登录后评论
9.6.2.修改方法
def acc_login(request): if request.method == 'POST': print(request.POST) user = authenticate(username=request.POST.get('username'), password=request.POST.get('password')) if user is not None: login(request,user) #return HttpResponseRedirect('/bbs') return HttpResponseRedirect(request.GET.get('next') or '/bbs') else: login_err = "Worng user name or password" return render(request,'login.html',{ 'login_err':login_err}) return render(request,'login.html')
9.6.3.评论测试
10.分级显示评论
10.1.增加展示方法
#!/usr/bin/env python# -*- coding: utf-8 -*-def add_node(tree_dic,comment): if comment.parent_comment is None: #我就是顶层,我放在这 tree_dic[comment] = {} else: #循环当前整个dict,直到找到为止 for k,v in tree_dic.items(): if k == comment.parent_comment:#找到爹了 tree_dic[comment.parent_comment][comment] = {} else:#进入下一层继续找 add_node(v,comment)def render_tree_node(tree_dic,margin_val): html = "" for k, v in tree_dic.items(): ele = "" % margin_val + k.comment + " %s" %k.date \ + " %s" %k.user.name +"" html += ele html += render_tree_node(v,margin_val+10) return htmldef render_comment_tree(tree_dic): html = "" for k,v in tree_dic.items(): ele = "" + k.comment + " %s" %k.date \ + " %s" %k.user.name + "" html += ele html += render_tree_node(v,10) return htmldef build_tree(comment_set): #print(comment_set) tree_dic = {} for comment in comment_set: add_node(tree_dic,comment) print("-"*10) for k,v in tree_dic.items(): print(k,v) return tree_dic
10.2.增加views方法
from django.shortcuts import renderfrom bbs import modelsfrom django.contrib.auth import login,logout,authenticatefrom django.contrib.auth.decorators import login_requiredfrom django.shortcuts import render,HttpResponse,HttpResponseRedirectfrom bbs import comment_handerimport jsoncategory_list = models.Category.objects.filter(set_as_top_menu=True).order_by("position_index")# Create your views here.def index(request): category_obj = models.Category.objects.get(position_index=1) article_list = models.Article.objects.filter(status='published') return render(request,'bbs/index.html',{ 'category_list':category_list, 'article_list': article_list, 'category_obj':category_obj })def category(request,id): category_obj = models.Category.objects.get(id=id) if category_obj.position_index == 1:#全部 article_list = models.Article.objects.filter(status='published') else: article_list = models.Article.objects.filter(category_id = category_obj.id,status='published') return render(request, 'bbs/index.html',{ 'category_list':category_list, 'category_obj':category_obj, 'article_list':article_list })def acc_login(request): if request.method == 'POST': print(request.POST) user = authenticate(username=request.POST.get('username'), password=request.POST.get('password')) if user is not None: login(request,user) #return HttpResponseRedirect('/bbs') return HttpResponseRedirect(request.GET.get('next') or '/bbs') else: login_err = "Worng user name or password" return render(request,'login.html',{ 'login_err':login_err}) return render(request,'login.html')def acc_logout(request): logout(request) return HttpResponseRedirect('/bbs')def article_detail(request,article_id): article_obj = models.Article.objects.get(id=article_id) #多级评论树 comment_tree = comment_hander.build_tree(article_obj.comment_set.select_related()) return render(request,'bbs/article_detail.html',{ 'article_obj':article_obj, 'category_list': category_list,})def comment(request): print(request.POST) if request.method == 'POST': new_comment_obj = models.Comment( article_id = request.POST.get('article_id'), parent_comment_id = request.POST.get('parent_comment_id') or None, comment_type = request.POST.get("comment_type"), user_id = request.user.userprofile.id, comment = request.POST.get("comment") ) new_comment_obj.save() return HttpResponse('success')def get_comments(request,article_id): article_obj = models.Article.objects.get(id=article_id) comment_tree = comment_hander.build_tree(article_obj.comment_set.select_related()) tree_html = comment_hander.render_comment_tree(comment_tree) return HttpResponse(tree_html)
10.3.增加url
from django.conf.urls import url,includefrom bbs import viewsurlpatterns = [ url(r'^$', views.index), url(r'category/(\d+)/$', views.category), url(r'detail/(\d+)/$', views.article_detail,name="article_detail"), url(r'comment/$', views.comment,name="post_comment"), url(r'^comment_list/(\d+)/$', views.get_comments,name="get_comments"),]
10.4.增加样式
.comment-node { border: 1px dashed blue; padding: 5px;}.root-comment { border: 1px dashed brown; padding: 5px;}
10.4.评论展示增加
{% extends 'base.html' %}{% load custom %}{% block page-container %}{ { article_obj.title }}作者:{ { article_obj.author.name }} { { article_obj.pub_date }} {% filter_comment article_obj as comments %} { { comments.comment_count }}{ { article_obj.content }}{% if request.user.is_authenticated %} {% else %}{% endif %}登录后评论
right{% endblock %}{% block bottom-js %}{% endblock %}
10.5.查看展示结果